"""
@File       :baidu_api.py
@Time       :2023/4/3 08:22
@Author     :yaoruiqi
@function   ：
"""
import asyncio
from json import loads, dumps

import httpx
from django.conf import settings
from django.core.cache import cache
from loguru import logger


class BaiduApi:

    def __init__(self):
        self.ak = settings.BAIDU_MAP_AK

    def geocoder(self, lon: str, lat: str):
        """
        经纬度获取地理详细信息
        @param lon: longitude经度
        @param lat: latitude纬度
        @return:
        """
        url = f'https://api.map.baidu.com/reverse_geocoding/v3/'
        params = {
            'ak': self.ak,
            'output': 'json',
            'coordtype': 'wgs84ll',
            'location': f'{lat},{lon}'

        }
        retry_times = 3
        for i in range(retry_times):
            try:
                response = httpx.get(url, params=params, timeout=30).json()
                assert response.get('status') == 0, f'获取经纬度信息失败，{response}'
                return response.get('result')
            except AssertionError as e:
                logger.error(f'{e}')
                return False
            except Exception as e:
                if i == retry_times - 1:
                    logger.exception(f'获取公众号所有订阅用户open_id失败，{e}')
                    return False

    def get_weather(self, adcode: str):
        """
        行政区号获取天气信息
        @param adcode: 行政区划编码
        @return:
        """
        url = f'https://api.map.baidu.com/weather/v1/?district_id={adcode}&data_type=all&ak={self.ak}'
        retry_times = 3
        for i in range(retry_times):
            try:
                response = httpx.get(url, timeout=30).json()
                assert response.get('status') == 0, f'行政区号获取天气信息失败，{response}'
                return response.get('result')
            except AssertionError as e:
                logger.error(f'{e}')
                return False
            except Exception as e:
                logger.exception(f'行政区号获取天气信息失败，{e}')

    async def async_get_weather(self, adcode: str):
        """
        异步行政区号获取天气信息
        @param adcode: 行政区划编码
        @return:
        """
        url = f'https://api.map.baidu.com/weather/v1/?district_id={adcode}&data_type=all&ak={self.ak}'
        retry_times = 3
        for i in range(retry_times):
            try:
                async with httpx.AsyncClient() as client:
                    response = await client.get(url, timeout=5)
                    response = response.json()
                    assert response.get('status') == 0, f'异步获取行政区号天气信息失败，{response}'
                    return adcode, response.get('result')
            except AssertionError as e:
                logger.error(f'{e}')
                return False
            except Exception as e:
                logger.exception(f'行政区号获取天气信息失败，{e}')


class PackageBaiduApi:
    @staticmethod
    async def async_get_weather(adcode: str, date_time: str = None, reset_cache: bool = False) -> tuple:
        """
        获取指定日期天气情况，根据情况更新缓存，缓存格式：weather_info_json:adcode
        @param adcode: 行政区号
        @param date_time: now或yyyy-MM-dd格式日期, now表示此刻，yyyy-MM-dd表示指定日期
        @param reset_cache: 是否重置缓存
        @return: 区域代码，天气信息
        """
        cahce_key = f'weather_info_json:{adcode}'
        if reset_cache:
            cache.delete(cahce_key)
        if weather_info := cache.get(cahce_key):
            weather_info_dict = loads(weather_info)
            if date_time is not None and (weather_info_date := weather_info_dict.get(date_time)):
                return adcode, weather_info_date
            else:
                return adcode, weather_info_dict

        for task_result in await asyncio.gather(*[baidu_api.async_get_weather(adcode)]):
            assert task_result, '行政区号获取天气信息失败'
            adcode, weather = task_result
            weather_format_info = {'now': weather['now'], 'location': weather['location']}
            for i in weather['forecasts']:
                weather_format_info[i['date']] = i
            cache.set(cahce_key, dumps(weather_format_info), 60 * 60 * 1)
            if date_time is not None:
                return adcode, weather_format_info[date_time]
            else:
                return adcode, weather_format_info

    @staticmethod
    def get_weather(adcode: str, date_time: str = None, reset_cache: bool = False) -> tuple:
        """
        获取指定日期天气情况，根据情况更新缓存，缓存格式：weather_info_json:adcode
        @param adcode: 行政区号
        @param date_time: now或yyyy-MM-dd格式日期, now表示此刻，yyyy-MM-dd表示指定日期
        @param reset_cache: 是否重置缓存
        @return: 区域代码，天气信息
        """
        cahce_key = f'weather_info_json:{adcode}'
        if reset_cache:
            cache.delete(cahce_key)
        if weather_info := cache.get(cahce_key):
            weather_info_dict = loads(weather_info)
            if date_time is not None and (weather_info_date := weather_info_dict.get(date_time)):
                return adcode, weather_info_date
            else:
                return adcode, weather_info_dict

        weather = baidu_api.get_weather(adcode)
        assert weather, '行政区号获取天气信息失败'
        weather_format_info = {'now': weather['now'], 'location': weather['location']}
        for i in weather['forecasts']:
            weather_format_info[i['date']] = i
        cache.set(cahce_key, dumps(weather_format_info), 60 * 60 * 1)
        if date_time is not None:
            return adcode, weather_format_info[date_time]
        else:
            return adcode, weather_format_info


baidu_api = BaiduApi()
package_baidu_api = PackageBaiduApi()
if __name__ == '__main__':
    # print(baidu_api.get_weather('110101'))
    # print(asyncio.run(package_baidu_api.async_get_weather('110101')))
    print(package_baidu_api.get_weather('110101'))
